﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;

namespace DadaLib
{
    /// <summary>
    /// Basic generator with a single input text.
    /// </summary>
    [Serializable]
    public class Generator : IGenerator
    {
        private readonly SortedDictionary<string, WeightedStringList> _dic;
        private string _lastWord;
        private readonly string _fileName;
        public bool Weighted { get; set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="Generator"/> class.
        /// </summary>
        public Generator()
        {
            _dic = new SortedDictionary<string, WeightedStringList>();
            Weighted = true;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Generator"/> class.
        /// </summary>
        public Generator(string fileName) : this()
        {
            _fileName = fileName;
        }


        public void Analize()
        {
            Analize(_fileName);
        }

        /// <summary>
        /// Analizes the input text to create internal structures.
        /// </summary>
        public void Analize(string fileName)
        {
            var parser = new FileParser(fileName);
            
            var word1 = parser.GetNextWord();
            while (true)
            {                
                var word2 = parser.GetNextWord();
                if ((word1 == null) || (word2 == null))
                    break;
                if (!_dic.ContainsKey(word1))
                    _dic[word1] = new WeightedStringList();
                _dic[word1].Insert(word2);
                word1 = word2;
            }
            _lastWord = SearchStartWord();
            _dic.Values.ToList().ForEach(x => x.Sort());
        }

        /// <summary>
        /// Gets the next word in sequence.
        /// </summary>
        /// <param name="seedWord">The seed word.</param>
        /// <returns></returns>
        public string GetNextWord(string seedWord)
        {
            if ((seedWord == null) || !_dic.ContainsKey(seedWord))
                return _dic.Keys.Last();
            var list = _dic[seedWord];
            _lastWord = Weighted? list.GetWeightedRandomString() : list.GetRandomString();
            return _lastWord;
        }

        /// <summary>
        /// Searches for a word suitable for starting a sentence.
        /// </summary>
        /// <returns>A word</returns>
        public string SearchStartWord()
        {
            string  word = GetNextWord(".");
            return word ?? GetNextWord(null);
        }

        public void SaveToFile(string fileName)
        {
            using (var outputStream = File.Create(fileName))
            {
                var ser = new BinaryFormatter();
                ser.Serialize(outputStream, this);
            }
        }

        public static Generator ReadFromFile(string fileName)
        {
            Generator generator;
            using (var inputStream = File.Open(fileName, FileMode.Open))
            {
                var ser = new BinaryFormatter();
                generator = (Generator)ser.Deserialize(inputStream);
            }
            return generator;
        }

    }
}
